<template>
  <!-- 头部区域 -->
  <home-head :today="today" />

  <!-- 轮播图 -->
  <section class="banner-box">
    <van-swipe :autoplay="3000" lazy-render v-if="banner.length > 0">
      <van-swipe-item v-for="item in banner" :key="item.id">
        <router-link :to="`/detail/${item.id}`">
          <img :src="item.image" alt="" class="pic" />
          <div class="desc">
            <h3 class="title">{{ item.title }}</h3>
            <p class="author">{{ item.hint }}</p>
          </div>
        </router-link>
      </van-swipe-item>
    </van-swipe>
  </section>

  <!-- 新闻列表 -->
  <van-skeleton title :row="5" v-if="list.length === 0"></van-skeleton>
  <template v-else>
    <section class="news-box" v-for="(item, index) in list" :key="item.date">
      <van-divider content-position="left" v-if="index !== 0">
        {{ formatTime(item.date, "{1}月{2}日") }}
      </van-divider>
      <div class="content">
        <news-item
          v-for="newsItem in item.stories"
          :key="newsItem.id"
          :data="newsItem"
        />
      </div>
    </section>
  </template>

  <!-- 加载更多 -->
  <div class="lazy-more" ref="loadBox" v-show="list.length > 0">
    <van-loading size="12px">小主,精彩数据准备中...</van-loading>
  </div>
</template>

<script>
import HomeHead from "@/components/HomeHead.vue";
import NewsItem from "@/components/NewsItem.vue";
import {
  reactive,
  toRefs,
  onBeforeMount,
  onMounted,
  onBeforeUnmount,
  ref,
} from "vue";
import api from "@/api";
import { formatTime } from "@/assets/utils";

export default {
  name: "Home",
  components: {
    HomeHead,
    NewsItem,
  },
  setup() {
    // 创建响应式状态
    let state = reactive({
      today: formatTime(true, "{0}{1}{2}"),
      banner: [],
      list: [],
    });

    // 获取加载更多的DOM盒子
    let loadBox = ref(null),
      ob = null;

    // 在第一次组件渲染之前:从服务器获取需要的数据
    onBeforeMount(async () => {
      let { date, stories, top_stories } = await api.queryNewsLatest();
      state.today = date;
      state.banner = Object.freeze(top_stories);
      state.list.push(
        Object.freeze({
          date,
          stories,
        })
      );
      // Object.freeze Vue的性能优化:对于从服务器获取的数据，如果后续没有修改其中某个字段让视图渲染的需求，最好冻结对象，这样避免响应式状态的深度劫持监听，可以提高很多性能!!
    });

    // 第一次组件渲染完:我们需要创建监听器,监听加载更多DOM元素出现在视口中（说明滚动到底部了）
    onMounted(async () => {
      ob = new IntersectionObserver(async (changes) => {
        // changes:数组,包含每一个监听的元素和可视窗口交叉状态信息
        // 监听DOM元素的同时会触发一次、当元素和可视窗口交叉状态改变会触发
        let change = changes[0];
        if (change.isIntersecting) {
          // 滚动到底部:加载以前的新闻信息
          let time = state.list[state.list.length - 1]["date"];
          let { date, stories } = await api.queryNewsBefore(time);
          state.list.push(
            Object.freeze({
              date,
              stories,
            })
          );
        }
      });
      ob.observe(loadBox.value);
    });
    // 组件销毁之前:把我们自己创建的监听器等释放掉
    onBeforeUnmount(() => {
      ob.unobserve(loadBox.value);
      ob = null;
    });

    // 返回的内容可以直接在视图中进行渲染「原理：返回的内容挂载到实例上」
    return {
      ...toRefs(state),
      loadBox,
      formatTime,
    };
  },
};
</script>

<style lang="less" scoped>
.banner-box {
  box-sizing: border-box;
  height: 375px;
  background: #eee;
  overflow: hidden;

  .van-swipe {
    height: 100%;

    a {
      display: block;
      height: 100%;
    }

    .pic {
      display: block;
      width: 100%;
      height: 100%;
    }

    .desc {
      position: absolute;
      bottom: 0;
      left: 0;
      box-sizing: border-box;
      padding: 20px;
      width: 100%;
      background: rgba(0, 0, 0, 0.5);
      background: -webkit-linear-gradient(
        top,
        rgba(0, 0, 0, 0),
        rgba(0, 0, 0, 0.5)
      );

      .title {
        line-height: 25px;
        font-size: 20px;
        color: #fff;
      }

      .author {
        line-height: 30px;
        font-size: 14px;
        color: rgba(255, 255, 255, 0.7);
      }
    }
  }

  /deep/.van-swipe__indicators {
    left: auto;
    right: 20px;
    transform: none;

    .van-swipe__indicator--active {
      background-color: #fff;
      width: 18px;
      border-radius: 3px;
    }
  }
}

.news-box {
  padding: 0 15px;

  .van-divider {
    margin: 5px 0;
    font-size: 12px;

    &:before {
      display: none;
    }
  }
}

.van-skeleton {
  padding: 30px 15px;
}

.lazy-more {
  display: flex;
  justify-content: center;
  align-items: center;
  box-sizing: border-box;
  padding: 0 10px;
  height: 50px;
  background: #f4f4f4;
}
</style>